#!/usr/bin/python3
# -*- coding: utf-8 -*-
# coding=utf-8
# Author: BillySir
from __future__ import print_function
from typing import *


class Chess:
    """棋子"""

    def __init__(self, name: Any, value: Any):
        super(Chess, self).__init__()
        self.name = name  # 用于识别和显示
        self.value = value  # 用于计算，如求和

    def __str__(self):
        return str(self.name)

    __repr__ = __str__


class ChessBasket:  # 棋子落在棋盘之前都放在棋盒，从棋盘上取走后也放在棋盒
    """棋盒"""

    def __init__(self, chess_dist: Mapping[Chess, int]):
        super(ChessBasket, self).__init__()
        self._chess_dist: Mapping[Chess, int] = chess_dist
        self._guess_count: int = 0

    @property
    def guess_count(self):
        return self._guess_count

    @property
    def get_chess_list_to_fill(self) -> List[Chess]:
        """获取可用的棋子集合"""
        return [item[0] for item in self._chess_dist.items() if item[1] > 0]

    def use_chess(self, chess) -> None:
        """使用一个棋子，数量减1"""
        if not isinstance(chess, Chess):  # 对非Chess（如数字常量，一般是Rule的Value)不作检查
            return
        count = self._chess_dist[chess]
        if count <= 0:
            raise Exception('unable to use %s. count left %d' % (str(chess), count))
        self._guess_count += 1
        count -= 1
        self._chess_dist[chess] = count

    def unuse_chess(self, chess) -> None:
        """不使用一个棋子，数量加1"""
        if not isinstance(chess, Chess):
            return
        count = self._chess_dist[chess]
        count += 1
        self._chess_dist[chess] = count

    def get_sum_min_n(self, n: int):
        """求value最小的前n个可用棋子的value之和"""
        total = 0
        count = 0
        for item in list(self._chess_dist.items()):
            if item[1] == 0:  # 可用数量
                continue
            count1 = min(item[1], n - count)
            total += item[0].value * count1
            count += count1
            if count == n:
                return total
        raise Exception("usable chess is not enough. expect:" + str(n) + ", actual:" + str(count))

    def get_sum_max_n(self, n: int):
        """求value最大的前n个可用棋子的value之和"""
        total = 0
        count = 0
        for item in reversed(list(self._chess_dist.items())):
            if item[1] == 0:  # 可用数量
                continue
            count1 = min(item[1], n - count)
            total += item[0].value * count1
            count += count1
            if count == n:
                return total
        raise Exception("usable chess is not enough. expect:" + str(n) + ", actual:" + str(count))

    def get_chess_by_name(self, name) -> List[Chess]:
        """获取指定name的可用棋子集合"""
        return [item[0] for item in self._chess_dist.items() if item[0].name == name and item[1] > 0]

    def get_chess_by_value(self, value) -> List[Chess]:
        """获取指定value的可用棋子集合"""
        return [item[0] for item in self._chess_dist.items() if item[0].value == value and item[1] > 0]

    def __str__(self):
        return str(self._chess_dist)

    __repr__ = __str__
